using System;

using net.windward.api.csharp;
using System.IO;

using System.Net;
using System.Data.Common;
using Microsoft.SharePoint.WebControls;
using net.windward.util;
using log4net;
using System.Security.Principal;
using System.Web;
using System.Threading;
using Microsoft.SharePoint;


namespace ArrowWebParts
{
    public partial class DisplayReport : LayoutsPageBase //System.Web.UI.Page
    {
        private static ILog log = LogManager.GetLogger(typeof(DisplayReport));

        private const string RPT_DOCX = "DOCX";
        private const string RPT_SML = "SML";
        private const string RPT_PDF = "PDF";
        private const string RPT_PPTX = "PPTX";
        private const string RPT_RTF = "RTF";
        private const string RPT_WML = "WML";
        private const string RPT_XLS = "XLS";
        private const string RPT_XLSX = "XLSX";

        private const string RPT_HTM = "HTM";
        private const string RPT_HTML = "HTML";
        private const string RPT_XHTML = "XHTML";

        private enum ReportFormat
        {
            DOCX,
            SML,
            PDF,
            PPTX,
            RTF,
            WML,
            XLS,
            XLSX,
            HTM,
            HTML,
            XHTML
        }

        private string passedFormat;
        private string passedRptName;
        String[] varValues;
        
        /* This calls Response.End() and swallows the ThreadAbortException that it throws.
         * See ms kb article 312629: http://support.microsoft.com/kb/312629.
         * If we don't call Response.End(), then user will get a "page can have only one server-side Form tag" exception.
         * */
        protected override void OnLoad(EventArgs e)
        {
            if (log.IsDebugEnabled)
                log.Debug("Running DisplayReport.");

            try
            {
                // read in license from web.config
                ArrowUtils.InitializeArrow(string.Concat(Page.Request.PhysicalApplicationPath, "\\web.config"));
            }
            catch (LicenseException lex)
            {
                ArrowUtils.LogFatalException(log, lex);
                Response.Write(string.Format("<html><body><p>License Error: {0}</p></body></html>", lex.Message));
                Response.End();
            }

            try
            {
                String passedRptDef = Request.QueryString["rptDef"];
                passedFormat = Request.QueryString["format"];
                passedRptName = Request.QueryString["rptName"];
                String passedNumVars = Request.QueryString["numvars"];
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("rptDef={0}", passedRptDef);
                    log.DebugFormat("format={0}", passedFormat);
                    log.DebugFormat("numvars={0}", passedNumVars);
                }

                int numVars = Convert.ToInt32(passedNumVars);
                varValues = new String[numVars];
                for (int i = 0; i < numVars; i++)
                {
                    varValues[i] = Request.QueryString["var" + i.ToString()];
                    if (log.IsDebugEnabled)
                        log.DebugFormat("var{0}={1}", i.ToString(), varValues[i]);
                }

                if (log.IsDebugEnabled)
                    log.Debug("Loading report definition.");
                String errorMessage;
                ReportDefinition reportDef = ArrowUtils.GetReportDefFromFile(passedRptDef, out errorMessage);

                if (log.IsDebugEnabled)
                    log.DebugFormat("Loading data definitions.");
                DataDefinition[] datasources = reportDef.getDataSources();

                generateReport(reportDef, datasources); // throws ThreadAbortException due to Response.End(); see above
            }
            catch (ThreadAbortException ex)
            {
                if (log.IsDebugEnabled)
                    log.Debug("ThreadAbortException on Response.End().", ex);
            }
            catch (Exception ex)
            {
                ArrowUtils.LogFatalException(log, ex);
                Response.Write(string.Format("<html><body><p>Error: {0}</p></body></html>", ex.ToString()));
                Response.End();
            }

            // this never gets hit because Response.End() throws ThreadAbortException
            //if (log.IsDebugEnabled)
            //    log.Debug("Finished running DisplayReport.");
        }
        /// <summary>
        /// Generates a report and writes the binary content to the Response.
        /// </summary>
        /// <param name="rptDef"></param>
        /// <param name="dataDefArray"></param>
        private void generateReport(ReportDefinition rptDef, DataDefinition[] dataDefArray)
        {
            if (log.IsDebugEnabled)
                log.Debug("Generating report");

            // get the template stream
            string templatePath = rptDef.template;
            if (log.IsDebugEnabled)
                log.DebugFormat("templatePath = {0}", templatePath);
            Stream templateStream = ArrowUtils.GetSPFileStream(templatePath);

            // get a report gen
            if (log.IsDebugEnabled)
                log.DebugFormat("passedFormat = {0}", passedFormat);
            Report reportGen = ArrowUtils.CreateReportGen(passedFormat, templateStream);

            // get the content type
            string contentType = GetContentType(passedFormat);

            // initialize the report gen
            if (log.IsDebugEnabled)
                log.Debug("Initializing report process.");
            reportGen.ProcessSetup();
            if (log.IsDebugEnabled)
                log.Debug("Finished initializing report process.");

            // map parameters
            KeyPairDictionary map = ArrowUtils.CreateVarMap(rptDef, varValues);
            ArrowUtils.AddCurrentUserInfoToReportVars(map);

            // process the data
            if (log.IsDebugEnabled)
                log.Debug("Processing data sources.");
            try
            {
                ArrowUtils.ProcessReportGenDataSources(reportGen, rptDef, dataDefArray, map, log);
            }
            catch (Exception e)
            {
                ArrowUtils.LogFatalException(log, e);
                Response.Write(string.Format("<html><body><p>Bad Datasource, verify the datasource credentials, and if xml, that the file still exists: {0}</p></body></html>", e.Message));
                Response.End();
                return;
            }
            if (log.IsDebugEnabled)
                log.Debug("Finished Processing data sources.");

            // finish processing the report
            if (log.IsDebugEnabled)
                log.Debug("Finishing report processing.");
            reportGen.ProcessComplete();
            if (log.IsDebugEnabled) {
                log.Debug("Finished report processing.");
                log.Debug("Writing report to web response.");
            }
            Response.ContentType = contentType;
            if (passedRptName == null)
                passedRptName = "report";
            if (!RPT_HTML.Equals(passedFormat, StringComparison.OrdinalIgnoreCase))
                Response.Headers.Set("content-disposition", "attachment; filename=\"" + passedRptName + ArrowUtils.GetRptFileExtension(passedFormat) + "\"");
            Response.BinaryWrite(((MemoryStream)reportGen.GetReport()).ToArray());
            reportGen.Dispose();

            // end the response
            if (log.IsDebugEnabled)
                log.Debug("Finished generating report.");
            Response.End();
        }
        /// <summary>
        /// Gets the content type string based on the report output format.
        /// </summary>
        /// <param name="rptFormat"></param>
        /// <returns></returns>
        private static string GetContentType(string rptFormat)
        {
            switch (rptFormat)
            {
                case RPT_DOCX:
                    return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
                case RPT_PDF:
                    return "application/pdf";
                case RPT_PPTX:
                    return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
                case RPT_RTF:
                    return "application/rtf";
                case RPT_SML:
                    return "application/vnd.ms-excel";
                case RPT_WML:
                    return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
                case RPT_XLS:
                    return "application/vnd.ms-excel";
                case RPT_XLSX:
                    return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                case RPT_HTML:
                    return "text/html";
                default:
                    throw new ArgumentException("Invalid report format: " + rptFormat);
            }
        }
    }
}